package com.probiz.estore.webapp.action;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;

import junit.framework.TestCase;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.support.XmlWebApplicationContext;

import com.probiz.estore.common.model.system.AppUser;
import com.probiz.estore.common.util.DateUtil;
import com.probiz.estore.core.model.BaseObject;
import com.probiz.estore.core.util.Log4jUtil;
import com.probiz.estore.core.util.StringUtil;
import com.probiz.estore.system.service.AppUserManager;

public abstract class BaseControllerTestCase extends TestCase {
	protected static XmlWebApplicationContext ctx;
	
	static long startTime;

	// This static block ensures that Spring's BeanFactory is only loaded
	// once for all tests
	static {
		System.out.println("Starting test case...");
		startTime = System.currentTimeMillis();
		Log4jUtil.initLogging(null);

		String[] paths = { "classpath*:conf/spring-context-test.xml", };

		ctx = new XmlWebApplicationContext();
		ctx.setConfigLocations(paths);
		ctx.setServletContext(new MockServletContext(""));
		ctx.refresh();
	}

	protected transient final Log logger = LogFactory.getLog(getClass());

	protected AppUser user;

	protected final void logDebug(String msg, Object... args) {
		if (logger.isDebugEnabled())
			logger.debug(StringUtil.format(msg, args));
	}

	protected final void logError(String msg, Object... args) {
		logger.error(StringUtil.format(msg, args));
	}

	protected void logInfo(String msg, Object... args) {
		if (logger.isInfoEnabled())
			logger.info(StringUtil.format(msg, args));
	}

	protected final void logWarn(String msg, Object... args) {
		if (logger.isWarnEnabled())
			logger.warn(StringUtil.format(msg, args));
	}

	protected MockHttpServletRequest newGet(String url) {
		return new MockHttpServletRequest("GET", url);
	}

	/**
	 * Convenience methods to make tests simpler
	 */
	protected MockHttpServletRequest newPost(String url) {
		return new MockHttpServletRequest("POST", url);
	}

	protected void objectToRequestParameters(Object o, MockHttpServletRequest request) throws Exception {
		objectToRequestParameters(o, request, null);
	}

	protected void objectToRequestParameters(Object o, MockHttpServletRequest request, String prefix) throws Exception {
		Class clazz = o.getClass();
		Field[] fields = getDeclaredFields(clazz);
		AccessibleObject.setAccessible(fields, true);

		for (int i = 0; i < fields.length; i++) {
			Object field = (fields[i].get(o));
			if (field != null) {
				if (field instanceof BaseObject) {
					objectToRequestParameters(field, request, fields[i].getName());
				} else if (!(field instanceof List) && !(field instanceof Set)) {
					String paramName = fields[i].getName();

					if (prefix != null) {
						paramName = prefix + "." + paramName;
					}

					String paramValue = String.valueOf(fields[i].get(o));

					// handle Dates
					if (field instanceof java.util.Date) {
						paramValue = DateUtil.convertDateToString((Date) fields[i].get(o));
						if ("null".equals(paramValue))
							paramValue = "";
					}

					request.addParameter(paramName, paramValue);
				}
			}
		}
	}

	protected void setUp() throws Exception {
		// populate the userForm and place into session
		AppUserManager userMgr = (AppUserManager) ctx.getBean("appUserManager");
		user = (AppUser) userMgr.getUserByName("admin");
	}

	private Field[] getDeclaredFields(Class clazz) {
		Field[] f = new Field[0];
		Class superClazz = clazz.getSuperclass();
		Collection rval = new ArrayList();

		if (superClazz != null) {
			rval.addAll(Arrays.asList(getDeclaredFields(superClazz)));
		}

		rval.addAll(Arrays.asList(clazz.getDeclaredFields()));
		return (Field[]) rval.toArray(f);
	}
	
	/* (non-Javadoc)
	 * @see junit.framework.TestCase#tearDown()
	 */
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
		logInfo("Test case completed, total time: [%1 secs].",((System.currentTimeMillis()-startTime)/1000));
	}

	public final static StringBuilder formatMsg(String msgWithFormat, Object... args) {
		return StringUtil.format(msgWithFormat, args);
	}
}
